home *** CD-ROM | disk | FTP | other *** search
/ Developer Helper 1: Phil & Dave's Excellent CD / Excellent CD HFS.raw / Moof / Goodies / HyperCard Goodies / AppleTalk Stuff / HyperAppleTalk / MISC / atalkXCMD.c < prev    next >
Text File  |  1988-05-12  |  38KB  |  1,346 lines

  1. /*******************************************************************\
  2. *    file:         atalkXCMD.c                                            *
  3. *    version:    1.06ß                                                 *
  4. *                                                                     *
  5. *                                                                    *
  6. * The following XCMD's give you AppleTalk capability (at the the     *
  7. * transaction and name-binding protocol layers) to Hypercard. While    *
  8. * not an exhaustive treatment, it's a start.                        *
  9. *                                                                    *
  10. * code known to work with correctly with the prototype as a client    *
  11. * and/or server                                                        *
  12. * -----------------------------------------------------------------    *
  13. *  Routine        |         Description                                *
  14. * -----------------------------------------------------------------    *
  15. *                                                                    *
  16. *            --- AppleTalk Transaction Protocol (ATP) Routines ---    *
  17. * ATPInit        Check to see if port available and appletalk drivers*
  18. *                loaded, allocate required buffers.  Open a server    *
  19. *                socket for this node.                                *
  20. * ATPKill        Disassociate ourselves with the    net deallocate        *
  21. *                buffers                                                *
  22. * PollRequests    Poll the Idle queue and return info                    *
  23. * Request        Determine whether a request can be sent or needs to    *
  24. *                be added to the waiting queue.                        *
  25. *                entity.                                                *
  26. *                                                                    *
  27. *            --- Name Binding Protocol (NBP) Routines ---            *
  28. * NBPInit        set up the NBP stuff                                 *
  29. * NBPKill        close down the NBP stuff                            *
  30. * ConfirmName    confirm that an entity is still visible (should be    *
  31. *                done before sending a message to that entity)        *
  32. * ExtractName    Extract a name from the Lookup buffer                *
  33. * Lookup        Look up other entities on the net and put the         *
  34. *                results in LookUpBuffer.                            *
  35. * NodeRegister    Get the name of this node and register it in the    *
  36. *                socket listening table.                                *
  37. *                                                                    *
  38. *            --- Miscellaneous Support Routines ---                    *
  39. * DeQueueRequest                                                    *
  40. *                Remove an element from waiting queue (FIFO style)    *
  41. * QueueGetRequest                                                    *
  42. *                Queue a GetRequest on the server side to "listen"     *
  43. *                for incoming client requests.                        *
  44. * QueueRequest    Queue a request that cannot be services due to lack    *
  45. *                of sockets.  Copy all the data into queue structure    *
  46. * Respond        Respond to a request with the given message            *
  47. * SendRequest    Set up an ATP parameter block and send the request    *
  48. * SendWaitingRequest                                                 *
  49. *                Attempt to send a queued request.  If successful,     *
  50. *                dequeue it, otherwise leave it in the queue for        *
  51. *                another try later.                                    *
  52. * -----------------------------------------------------------------    *
  53. * By:    Donald Koscheka                                                *
  54. *        with Gratitudes to Kerry Lynn for debugging help            *
  55. *        and Platitudes to Greg Kimberly for thinking up the idea    *
  56. * Date:    21-Sept-87                                                    *
  57. * ©    Copyright 1987, Apple Computer, Inc.                            *
  58. *    All Rights Reserved                                                *
  59. *                                                                    *
  60. * -----------------------------------------------------------------    *
  61. *                        Modification History                        *
  62. * -----------------------------------------------------------------    *
  63. *  Date           | By    |                     Description                    *
  64. * -----------------------------------------------------------------    *
  65. * 9/21/87    | DK    | file created                                    *
  66. * 10/1/87    | DK    | modified to work with preferred ATP calls        *
  67. * 10/5/87    | DK    | relocate the master block at heap high        *
  68. * 10/6/87    | DK    | added dynamically allocated lookup buffer        *
  69. * 10/7/87    | DK     | separated response from Poll Request            *    
  70. * 10/7/87    | DK    | extract responses during Poll_Requests        *
  71. * 11/5/87    | DK    | modified all routines to return the error        *
  72. *            | DK    | removed paramBlock from all calls not making    *
  73. *            |        | callbacks to hypercard.                        *
  74. *            |        | modified code to reflect changes in 11/5 spec    *
  75. * -----------------------------------------------------------------    *
  76. *                    Alpha Release 0.5    11/30/87                    *
  77. * -----------------------------------------------------------------    *
  78. * 12/1/87    | DK    | Modified receive to put received data in        *
  79. *            |         | global pool and call back with method only    *
  80. * 12/2/87    | DK    | Modified waiting queue to act as a FIFO        * 
  81. *             | DK    | issue responses asynchronously.                *
  82. * 12/3/87    | DK    | Added full response packet transmission        *
  83. * 12/7/87    | DK    | Converted NBP calls to preferred (paramblock)    *
  84. * 12/10/87    | DK    | General bug fixes - check handles...            *
  85. * 12/11/87    | DK    | converted nonrels from locked handles to Ptrs    *
  86. * -----------------------------------------------------------------    *
  87. *                    Beta Release 1.05ß    12/15/87                    *
  88. * -----------------------------------------------------------------    *
  89. *  1/14/88    | DK    | Converted all routines to access names table    *
  90. *            |        | Uncouple NBP and ATP stuff                    *
  91. *  1/26/88    | DK    | set SPConfigP to 0x01 to indicate Appletalk is*
  92. *            |        | is using port B                                *
  93. *  2/10/88    | DK    | Set atp.checkpoint flag to signal that we're     *
  94. *            |        | currently in ATPReceive (ATPClose can't close)*
  95. *            |        | or ATPClose sets to tell ATPReceive to close    *
  96. * 22-Feb-88 | DK    | Move all locked handles high                    *
  97. * 29-Feb-88    | DK    | Dispose handle created for response callback    *
  98. * -----------------------------------------------------------------    *
  99. \*******************************************************************/
  100.  
  101. /*******************************************************************\
  102. * HUH???? Experienced "C" programmers will note the capricious        *
  103. * use of the commented "auto" storage class.  I do this so that     *
  104. * my data declarations "line up" as: CLASS TYPE NAME = INITIALIZER    *
  105. * This pedantry is provided as an aid to the beginner.  Also,         *
  106. * remembering that automatics are stack-bound might help the novice    *
  107. * look for them in a stack frame from the debugger(Hint: A6 is the    *
  108. * frame pointer).                                                   *
  109. *                                                        -DK            *
  110. \*******************************************************************/
  111.  
  112.  
  113. #include    <Types.h>
  114. #include     <AppleTalk.h>
  115. #include    <Resources.h>
  116. #include     <OSUtils.h>
  117. #include    <Memory.h>
  118. #include    <Strings.h>
  119. #include    "atalkxcmd.h"
  120. #include    "xcmdutils.h"
  121. #include     "HyperXCmd.h"
  122.  
  123.  
  124. /*******************************************************************\
  125. *    AppleTalk Transaction Protocol (ATP) Interface Routines            *
  126. *                                                                    *
  127. \*******************************************************************/
  128.  
  129. ATPBlock    *ATPInit( entcount, type )
  130.     short            entcount;
  131.     short            type;
  132. /*********************************
  133. * Check to see if PortB is in use by
  134. * a serial driver or wheter it is 
  135. * available to us for appletalk.  If
  136. * it is available, check PortBUse to
  137. * determine whether appletalk is in.
  138. *
  139. * Allocate our buffers and open a 
  140. * listening socket for this node 
  141. * (talkers are allocated dynamically).
  142. * queue up enough requests to get
  143. * us going...
  144. *
  145. * In:         short = number of entitities
  146. *            to allocate
  147. *
  148. * Out:        Pointer to the allocated ATPBlock
  149. *            nil of the session was already initialized
  150. *
  151. * NOTE: We attempt to allocate (3) 
  152. *        nonrels - ATPBlock, ServerBlock
  153. *        and ClientBlock.  These objects
  154. *        MUST NOT move during the session
  155. *        (async I/O is depending on it)
  156. *********************************/
  157. {
  158.     /* auto */        char            *PortBUseP;
  159.     /* auto */        char            *SPConfigP;
  160.     /* auto */        char            use, con;
  161.     /* auto */        char            *temp;
  162.     /* auto */        OSErr            error;    
  163.     /* auto */        short            i;
  164.     /* auto */        ATPParamBlock    pb;
  165.     register        ATPBlock        *mbPtr;
  166.     
  167.     /* point to and get the needed lowmem stuff.  */
  168.     PortBUseP = (char *)PortBUse;
  169.     SPConfigP = (char *)SPConfig;
  170.     use = *PortBUseP;
  171.     con = *SPConfigP;
  172.     
  173.     if((con & 0x0F) > useATalk) /** if the port is in use we can't usurp it **/ 
  174.         return( nil );
  175.     
  176.     if( (use & 0xFF || use & 0x0F) == useATalk){
  177.         if(!IsMPPOpen())
  178.             if((error = MPPOpen()) != noErr)
  179.                 return( nil );
  180.     
  181.         if( !IsATPOpen() ){
  182.             if (error = ATPLoad() != noErr)
  183.                 return( nil );
  184.         
  185.             *PortBUseP |= 0x04;
  186.             *PortBUseP &= 0x7F;
  187.         }
  188.     }
  189.     else
  190.         return( nil );
  191.  
  192.     *SPConfigP |= 0x01;    /*** set for appletalk     ***/
  193.  
  194.     /*** attempt to allocate the data                 ***/
  195.     if( !(mbPtr    = (Ptr)NewPtr( sizeof( ATPBlock ))) )
  196.         return( nil );
  197.  
  198.     /***             ------    Initialize the Master Block ------            ***/
  199.     mbPtr->Server            = nil;
  200.     mbPtr->Client            = nil;
  201.     mbPtr->FirstRequest     = nil;        /***  no requests queued         ***/
  202.     mbPtr->LastRequest         = nil;
  203.     mbPtr->checkPoint        = CLOSE_OK;    /**** 2/10/88                    ***/
  204.     
  205.     temp = mbPtr->autoRsp;
  206.     *temp++ = 'O';                    /*** if you receive this message     ***/
  207.     *temp++ = 'K';                    /*** from a callback, you know the     ***/
  208.     *temp++ = 'A';                    /*** transaction succeeded.          ***/
  209.     *temp++ = 'Y';                    /*** Isn't that special?            ***/
  210.     *temp  = '\0';
  211.                     
  212.     /***             ------    Initialize the server side    ------            ***/
  213.     mbPtr->ServerAddr.aSocket = 0;
  214.     mbPtr->ServerAddr.aNode = 0;
  215.     mbPtr->ServerAddr.aNet = 0;
  216.  
  217.     if( type && SERVER ){
  218.         pb.ATPaddrBlock.aNet     = (short)0;
  219.         pb.ATPaddrBlock.aNode    = 0;
  220.         pb.ATPaddrBlock.aSocket    = 0;
  221.         pb.ATPatpSocket            = 0;
  222.  
  223.         if( !POpenATPSkt( &pb , SYNC ) )    /*** noErr means we have a socket***/
  224.             mbPtr->ServerAddr.aSocket    = (unsigned char)pb.ATPatpSocket;
  225.         else{
  226.             ShutMeDown( mbPtr );
  227.             return( nil );
  228.         }
  229.         
  230.         /*** initialize getrequests array ***/
  231.         {    
  232.             register    ServerPtr    sp = mbPtr->Server;
  233.             
  234.             mbPtr->Server = (ServerPtr)NewPtr( sizeof( ServerBlock )*SQSIZE );
  235.             if( mbPtr->Server )
  236.                 sp = mbPtr->Server;
  237.             else{
  238.                 ShutMeDown( mbPtr );
  239.                 return( nil );
  240.             }    
  241.             for( i=0; i < SQSIZE; i++ )
  242.                 QueueGetRequest( &(sp[i]), &(mbPtr->ServerAddr) );
  243.         }
  244.     }
  245.     
  246.     /***             ------    Initialize the client side    ------                ***/
  247.     if(  type && CLIENT ){                    
  248.         /*** initialize the send request queue ***/
  249.         {    
  250.             ClientPtr    cp;
  251.         
  252.             mbPtr->Client = (ClientPtr)NewPtr( sizeof( ClientBlock ) * CQSIZE );
  253.             if( mbPtr->Client )
  254.                 cp = mbPtr->Client;
  255.             else{
  256.                 ShutMeDown( mbPtr );
  257.                 return( nil );
  258.             }
  259.             for( i=0; i < CQSIZE; i++ ){
  260.                 cp[i].isInUse    = IDLE;
  261.                 cp[i].rspM        = nil;
  262.             }
  263.         }
  264.     }
  265.     return( mbPtr );
  266. }
  267.  
  268.  
  269. ShutMeDown( atp )
  270.     ATPBlock        *atp;
  271. /****************************
  272. * Given a handle to an allocated
  273. * ATPBlock, deallocate all its
  274. * substructures and itself
  275. *
  276. * called only after a memory failure
  277. * and atp already allocated.
  278. ****************************/
  279. {
  280.     if( atp->Server )
  281.         DisposPtr( atp->Server );
  282.     
  283.     if( atp->Client )
  284.         DisposPtr( atp->Client );
  285.  
  286.     DisposPtr( atp );
  287. }
  288.  
  289.  
  290. short    ATPKill(  atp )
  291.     ATPBlock        *atp;
  292. /*********************************
  293. * Remove ourselves from the entity
  294. * table, dislocate our socket and 
  295. * deallocate all memory whose handles
  296. * were provided...
  297. *
  298. * In:         Handle to ATPBlock
  299. *
  300. * Out:        noErr if successful
  301. *            OSErr otherwise
  302. *********************************/
  303. {
  304.     /* auto */    OSErr            error = noErr;
  305.     /* auto    */    OSErr            err;
  306.     /* auto */    short            i;
  307.     /* auto */    ATPParamBlock    pb;
  308.  
  309.     /***     Close Down and Deallocate the SERVER side     ***/
  310.     if( atp->Server ){
  311.         register    ServerPtr    sp = atp->Server;
  312.         
  313.         if( atp->ServerAddr.aSocket ){
  314.             /*** close down any outstanding get requests***/
  315.  
  316.             for( i = 0; i < SQSIZE; i++ )
  317.                 if( sp[i].isInUse && sp[i].pb.ATPioResult > 0 ){
  318.                     pb.ATPaKillQEl = &(sp[i].pb);
  319.                     err = PKillGetReq( &pb, SYNC );
  320.                     if( err )
  321.                         error = err;
  322.                 }
  323.             
  324.             /*** shut down the server socket             ***/
  325.             pb.ATPatpSocket = atp->ServerAddr.aSocket;
  326.             err = PCloseATPSkt( &pb, SYNC );
  327.             if( err )
  328.                 error = err;
  329.         }
  330.     }
  331.     
  332.     /***     Close Down and Deallocate CLIENT side         ***/
  333.     if( atp->Client ){        
  334.         register    ClientPtr    cp = atp->Client;
  335.         
  336.         /*** Kill outstanding SendRequests                 ***/
  337.         for( i = 0; i < CQSIZE; i++ )
  338.             if( cp[i].isInUse && cp[i].pb.ATPioResult > 0 ){
  339.                 pb.ATPaKillQEl = &(cp[i].pb);
  340.                 err = PKillSendReq( &pb, SYNC );
  341.                 if( err )
  342.                     error = err;
  343.  
  344.                 if( cp[i].rspM ){
  345.                     HUnlock( cp[i].rspM );
  346.                     DisposHandle( cp[i].rspM );
  347.                 }
  348.             }
  349.         
  350.         /*** deallocate all waiting queue elements         ***/
  351.         if( atp->FirstRequest ){
  352.             /* auto */    ClientQH    nq, cq;
  353.             register    ClientQPtr    pq;
  354.         
  355.             cq = atp->FirstRequest;
  356.             
  357.             while( cq ){
  358.                 nq = (**cq).next;
  359.                 pq = *cq;
  360.                 
  361.                 if( pq->rsp ){
  362.                     HUnlock( pq->rsp );
  363.                     DisposHandle( pq->rsp );
  364.                 }
  365.                 
  366.                 if( pq->buf ){
  367.                     HUnlock( pq->buf );
  368.                     DisposHandle( pq->buf );
  369.                 }
  370.                 HUnlock( cq );
  371.                 DisposHandle( cq );
  372.                 cq = nq;
  373.             }
  374.         }
  375.     }
  376.     ShutMeDown( atp );
  377.     return( error );
  378. }
  379.  
  380.  
  381. short    PollRequests( paramPtr, atp, rspMess )
  382.     XCmdBlockPtr    paramPtr;
  383.     ATPBlock        *atp;
  384.     Handle            rspMess;
  385. /*********************************
  386. * PollRequests
  387. *
  388. * Performs 3 functions:
  389. *
  390. * (1) Handle Received Requests on Server Side
  391. *
  392. * (2) Handle Succesful termination of Responses
  393. *
  394. * (3) Handle Received Responses on Client Side
  395. *
  396. *********************************/
  397. {
  398.     /* auto */    OSErr    error = noErr;
  399.     /* auto */    short    i;
  400.  
  401.     if( atp->Server  ){
  402.         error = Get_Requests_From_Clients( paramPtr, atp, rspMess );
  403.         error = Check_Response_Sent( paramPtr, atp );
  404.     }
  405.     
  406.     if( atp->Client )
  407.         error = Get_Responses_From_Servers( paramPtr, atp );
  408.         
  409.     if( error > 0 ) 
  410.         error = 0;
  411.     return(  error );
  412. }
  413.  
  414.  
  415. short    Request(  atp, theData, theSize, addr, rmess, cnt, intv )
  416.     ATPBlock        *atp;
  417.     unsigned char    *theData;
  418.     short            theSize;
  419.     AddrBlock        *addr;
  420.     Handle            rmess;
  421.     short            cnt, intv;
  422. /*********************************
  423. * If a transaction block is available,
  424. * send the request on to ATP.  Otherwise,
  425. * add it to the waiting queue.
  426. *
  427. * In:        theData        == the data to use
  428. *            theSize        == the size of the data
  429. *            rmess        == handle to the message to 
  430. *                           append the response to
  431. *            addr        == tuple of the receiver
  432. *            retry, timeout
  433. *
  434. * Out:        noErr if successful
  435. *            OSErr otherwise
  436. *********************************/
  437. {
  438.     /* auto */    OSErr        error = noErr;
  439.     /* auto */    short        i;
  440.     register    ClientPtr    cp    = atp->Client;
  441.     
  442.     if( !atp->Client )                    /*** take a powder you chowder head     ***/
  443.         return( DEFAULT_ERROR );
  444.         
  445.     /*** find the next available client transaction block (if any)                ***/
  446.     for( i = 0; i < CQSIZE; i++ )
  447.         if(  cp[i].isInUse == IDLE ){
  448.             error = SendRequest( &(cp[i]),theData, theSize, rmess, addr, cnt, intv );
  449.             return( error );
  450.         }
  451.         
  452.     /*** didn't have an available transaction block, or the request failed to    ***/
  453.     /*** to get satisfied (probably no available sockets), so pend the request    ***/
  454.     QueueRequest( atp, theData, theSize, rmess, addr, cnt, intv );
  455.  
  456.     return( noErr );        /*** queued requests don't fail                        ***/
  457. }
  458.  
  459.  
  460. /*******************************************************************\
  461. *                 PollRequests Server/Client Routines                    *
  462. \*******************************************************************/
  463.  
  464.  
  465. Get_Requests_From_Clients( paramPtr, atp, rspMess )
  466.     XCmdBlockPtr    paramPtr;
  467.     ATPBlock        *atp;
  468.     char            **rspMess;
  469. /*********************************
  470. * Get_Requests_From_Clients
  471. *
  472. * For all elements in the getRequest queue:
  473. * if a getRequest is completed:
  474. *    - get the request data and put it into the global receive container
  475. *    - call hypercard back with the getrequest message
  476. *    - the responding method will put the response in "GlobalRSPData"
  477. *    - if the response message is nil, do an auto respond
  478. *      else send the response in the global container "GlobalRSPData"
  479. *    - deallocate the request and requeue a fresh one
  480. *
  481. * In:         paramPtr    = used for callbacks
  482. *            atp        = ATPBlock pointer
  483. *            rspMess    = message to send back to 
  484. *                          hypercard with Server-side getrequests.
  485. *
  486. * Out:        calls back hypercard with the request
  487. *            error result returned.
  488. *********************************/
  489. {    
  490.     /* auto */    short        i;
  491.     /* auto */    OSErr        error = noErr;
  492.     /* auto */    long        rs;
  493.     /* auto */    Handle        name, respData;
  494.     /* auto */    long        respSize;
  495.     register    ServerPtr    sp;
  496.  
  497.     if( rspMess )
  498.         c2pstr( *rspMess );
  499.             
  500.     sp = atp->Server;
  501.     for( i = 0;  i < SQSIZE ;  i++ ){
  502.         error = sp[i].pb.ATPioResult;                    /*** didn't take***/
  503.         if( sp[i].isInUse == WAIT_REQUEST ){
  504.             if( error < 0 )
  505.                 QueueGetRequest( &(sp[i]), &(atp->ServerAddr) );/*** try again    ***/
  506.             else
  507.                 if( !error ){
  508.                     /*** put the request in a Hypercard global                ***/
  509.                     name = GetResource('STR ', GlobalRcvData );     
  510.                     respSize = (long)sp[i].pb.ATPreqLength;
  511.                     respData = NewHandle( respSize );
  512.                     BlockMove( sp[i].pb.ATPreqPointer, *respData, respSize );
  513.                     MoveHHi( name );
  514.                     HLock(name);    
  515.                     SetGlobal( paramPtr, *name, respData ); 
  516.                     HUnlock(name);
  517.                     DisposHandle( respData ); /* 2/29/88 */
  518.                     
  519.                     /*** now call the responding method (if any)            ***/
  520.                     if(  rspMess ){
  521.                         MoveHHi( name );
  522.                         HLock( rspMess );
  523.                         SendCardMessage( paramPtr, *rspMess );
  524.                         HUnlock( rspMess );
  525.                     }
  526.                     
  527.                     /*** if the responding method has a response to send    ***/
  528.                     /*** then send it, otherwise "autorespond" using the    ***/
  529.                     /*** canned response "OKAY"                                ***/
  530.                     name = GetResource('STR ',GlobalRspData );     
  531.                     MoveHHi( name );
  532.                     HLock(name);                                            
  533.                     respData = GetGlobal(paramPtr,*name); 
  534.                     HUnlock(name);    
  535.                 
  536.                     if ( respData && **respData ){
  537.                         rs = GetHandleSize( respData );
  538.                         MoveHHi( respData );
  539.                         HLock( respData );
  540.                         Respond(  &(sp[i]), &(atp->ServerAddr), *respData, (short)rs );
  541.                         HUnlock( respData );
  542.                     }
  543.                     else                        /***  send the autoresponse     ***/
  544.                         Respond( &(sp[i]),&(atp->ServerAddr),atp->autoRsp,(short)AUTOSIZE);
  545.  
  546.                     if( respData )
  547.                         DisposHandle( respData ); /* 2/29/88 */
  548.             }
  549.         }
  550.     }/*** for loop ***/        
  551. }
  552.  
  553.  
  554. Check_Response_Sent(paramPtr, atp )
  555.     XCmdBlockPtr    paramPtr;
  556.     ATPBlock        *atp;
  557. /*********************************
  558. * Send_Responses_To_Clients
  559. *
  560. * A server transaction block is considered
  561. * in use from the time that the get request
  562. * is queued unitl the TREL is received from 
  563. * the client (acknowledging receipt of the 
  564. * response).
  565. *
  566. * Actually, all this routine does is wait
  567. * for the sent response to complete and
  568. * requeue a get request when it does.
  569. *
  570. * In:         paramPtr    = used for callbacks
  571. *            atp        = ATPBlock pointer
  572. *
  573. *********************************/
  574. {
  575.     /* auto */    short        i;
  576.     /* auto */    OSErr        error = noErr;
  577.     register    ServerPtr    sp;
  578.  
  579.     /*** See if any Responses have completed    ***/
  580.     sp = atp->Server;
  581.     for( i = 0; i < SQSIZE; i++ )
  582.         if( sp[i].isInUse == WAIT_RESPONSE )
  583.             /*** waiting for the client to acknowledge receipt ***/
  584.             if( sp[i].pb.ATPioResult <= 0 ){
  585.                 error = sp[i].pb.ATPioResult;
  586.                 sp[i].isInUse == IDLE;
  587.                 QueueGetRequest( &(sp[i]), &(atp->ServerAddr) );
  588.             }
  589. }
  590.  
  591.  
  592. Get_Responses_From_Servers(paramPtr, atp  )
  593.     XCmdBlockPtr    paramPtr;
  594.     ATPBlock        *atp;
  595. /*********************************
  596. * Get_Responses_From_Servers
  597. *
  598. * For all elements in the request queue:
  599. * if a sndRequest completes:
  600. *    - get the responding data and put it into the global receive containter
  601. *    - if the request contained a response message, call hypercard back
  602. *      with the message.
  603. *    - dequeue this request
  604. *
  605. * In:         paramPtr    = used for callbacks
  606. *            atp            = ATPBlock pointer
  607. *
  608. * Out:        calls back hypercard with the request
  609. *            error result returned.
  610. *********************************/
  611. {
  612.     /* auto */    short        i,j;
  613.     /* auto */    OSErr        error     = noErr;
  614.     /* auto */    ClientPtr    cp;
  615.     /* auto */    Handle        name, RcvData;
  616.     register    char        *respData;
  617.     register    short        respSize;
  618.  
  619.     cp    = atp->Client;
  620.     for( i = 0; i < CQSIZE; i++ )
  621.         if( cp[i].isInUse == IDLE )
  622.             SendWaitingRequest( atp, &(cp[i]) );
  623.         else{
  624.             if( cp[i].pb.ATPioResult < 0 ){
  625.                 /*** next user of the block will clean up the dangling data    ***/
  626.                 cp[i].isInUse = IDLE;
  627.                 error = cp[i].pb.ATPioResult;
  628.                 if( cp->rspM ){
  629.                     HUnlock( cp->rspM );
  630.                     DisposHandle( cp->rspM );
  631.                     cp->rspM = nil;
  632.                 }
  633.             }
  634.             if(  cp[i].pb.ATPioResult == 0 ){
  635.                 /*** got an answer from the server...                            ***/
  636.                 /***                                                            ***/
  637.                 /*** To calculate the size, add up the sizes of each BDS        ***/
  638.                 /*** element. The buffers are contiguous so we don't have        ***/
  639.                 /*** to concatentate them to create the response message        ***/
  640.                 cp[i].isInUse = IDLE;
  641.                  respData     = (cp[i]).bds[0].buffPtr;
  642.                 respSize    = 0;
  643.             
  644.                 for( j = 0; j < (short)cp[i].pb.ATPnumOfResps; j++ )
  645.                     respSize += cp[i].bds[j].dataSize;
  646.                 
  647.                 /*** put the responding data in global  pool and call back        ***/
  648.                 /*** hypercard with the response message                         ***/            
  649.                 name = (StringPtr *)GetResource('STR ', GlobalRcvData );     
  650.                 RcvData = NewHandle( (long)respSize );
  651.                 
  652.                 if( RcvData ){
  653.                     BlockMove( respData, *RcvData, (long)respSize );
  654.                     MoveHHi( name );
  655.                     HLock(name);            
  656.                     SetGlobal(paramPtr, *name, RcvData ); 
  657.                     HUnlock(name);
  658.                     DisposHandle( RcvData ); /* 2/29/88 */
  659.                 }
  660.                 
  661.                 /*** If response message was given, call back hypercard with    ***/
  662.                 /*** the message (handler finds its data in GlobalRcvData)        ***/
  663.                 if( cp[i].rspM ){
  664.                     MoveHHi( cp[i].rspM );
  665.                     HLock( cp[i].rspM );
  666.                     c2pstr( *(cp[i].rspM) );                
  667.                     SendCardMessage( paramPtr, *(cp[i].rspM) );
  668.                     HUnlock( cp[i].rspM );
  669.                     DisposHandle( cp[i].rspM );
  670.                     cp[i].rspM = nil;
  671.                 }
  672.             }
  673.         }
  674.     return( error );
  675. }
  676.  
  677.  
  678. /*******************************************************************\
  679. *                 (ATP) Interface Support Routines                    *
  680. *                                                                    *
  681. * These routines are used in support of the ATP Interface routines    *
  682. * and are not called directly by the XCMD routines.                    *
  683. \*******************************************************************/
  684.  
  685.  
  686. DeQueueRequest( atp  )
  687.     ATPBlock        *atp;
  688. /*********************************
  689. * Remove an element from the waiting 
  690. * queue and update the linked list 
  691. * accordingly.
  692. *
  693. * Note: this is the only place an element can 
  694. *         be removed from the queue.  We use a FIFO
  695. *        method so that tq is ALWAYS pointing to
  696. *        the first element in the list!
  697. *
  698. * In:     tq = handle to the element 
  699. *        to dequeue
  700. *********************************/
  701. {
  702.     register    ClientQH        tq = atp->FirstRequest;
  703.     register    ClientQPtr        pq; /*** pointer for efficiency     ***/
  704.         
  705.     if( !tq ){
  706.         atp->FirstRequest = atp->LastRequest = nil;
  707.         return;                        /*** No queue element here            ***/
  708.     }
  709.     
  710.     pq    = *tq;
  711.                                             /*** next becomes first     ***/
  712.     if( pq->next )                            /*** if there is one        ***/
  713.         atp->FirstRequest = pq->next;
  714.     else                            /*** ...else the list is empty        ***/
  715.         atp->FirstRequest = atp->LastRequest = nil;
  716.  
  717.     if( pq->buf ){
  718.         HUnlock( pq->buf );            /*** Delete the element's data        ***/
  719.         DisposHandle( pq->buf );        
  720.     }
  721.     
  722.     if( pq->rsp ){
  723.         HUnlock( pq->rsp );
  724.         DisposHandle( pq->rsp );
  725.     }
  726.     
  727.     HUnlock( tq );
  728.     DisposHandle( tq );        
  729. }
  730.  
  731.  
  732. QueueGetRequest( sp, srcaddr )
  733.     ServerPtr        sp;
  734.     AddrBlock        *srcaddr;
  735. /*********************************
  736. * requeue the  get request element
  737. * whose index is passed as a param.
  738. *
  739. * Note: This is a server side 
  740. * function only. You may 
  741. * have more than one getrequest
  742. * "listening" on the server socket.
  743. *
  744. * if the request if not completed,
  745. * do nothing.
  746. *
  747. * In:    sp        == pointer to request array element
  748. *        srcaddr == source address of this node
  749. *
  750. * returns nil if the request was queued
  751. * noErr otherwise
  752. *********************************/
  753. {
  754.     /*auto */    short        error     = DEFAULT_ERROR;
  755.     register    atpPBptr    pb        = &(sp->pb);
  756.  
  757.     pb->ATPioCompletion    = nil;
  758.     pb->ATPatpSocket    = srcaddr->aSocket;
  759.     pb->ATPreqLength    = (short)ATPBSIZE;
  760.     pb->ATPreqPointer    = sp->buf;
  761.     sp->isInUse         = WAIT_REQUEST;        /*** set for the sake of Kill    ***/
  762.         
  763.     if( (error = PGetRequest( pb , ASYNC ))  >= 0 )
  764.         error = noErr;
  765.  
  766.     return( error );
  767. }
  768.  
  769.  
  770. QueueRequest( atp, theData, theSize, rmess, addr, cnt, intv )
  771.     ATPBlock        *atp;
  772.     unsigned char    *theData;
  773.     short            theSize;
  774.     Handle            rmess;
  775.     AddrBlock        *addr;
  776.     short            cnt, intv;
  777. /*********************************
  778. * Add an element to the waiting 
  779. * queue and update the linked list 
  780. * accordingly.
  781. *
  782. * Note: this is the only place an element can 
  783. *         be added to the queue.
  784. *
  785. * In:        theData        == the data to use
  786. *            theSize        == the size of the data
  787. *            rmess        == handle to the message to 
  788. *                           append the response to
  789. *            addr        == tuple of the receiver
  790. *            retry, timeout
  791. *********************************/
  792. {
  793.     /* auto */    long        respSize;                
  794.     /* auto */    ClientQH    qelem;
  795.     register    ClientQPtr    qp;                    /*** ptr to client queue element***/
  796.  
  797.     if( (qelem = NewHandle( sizeof( ClientQRec ))) == nil )
  798.         return( DEFAULT_ERROR );
  799.     
  800.     /*** copy the pending data into the qelement ***/
  801.     MoveHHi( qelem );
  802.     HLock( qelem );
  803.     qp                = *qelem;
  804.     qp->next         = nil;
  805.     qp->interval     = intv;
  806.     qp->count         = cnt;
  807.     qp->addr.aNet     = addr->aNet;
  808.     qp->addr.aNode    = addr->aNode;
  809.     qp->addr.aSocket= addr->aSocket;
  810.     qp->size         = (long)theSize;
  811.     qp->rsp         = nil;
  812.     qp->buf         = NewHandle( qp->size );
  813.     
  814.     if( qp->buf  )
  815.         BlockMove( theData, *(qp->buf), qp->size );
  816.     else{
  817.         HUnlock( qelem );
  818.         DisposHandle( qelem );
  819.         return( MEM_ERROR );
  820.     }
  821.  
  822.     if( rmess  ){        /*** if we have a handle and it's not empty        ***/
  823.         respSize = GetHandleSize( rmess );
  824.         qp->rsp = NewHandle( respSize );
  825.         if( qp->rsp )
  826.             BlockMove( *rmess, *(qp->rsp), respSize );
  827.         else{
  828.             HUnlock( qp->buf );
  829.             DisposHandle( qp->buf );
  830.             HUnlock( qelem );
  831.             DisposHandle( qelem );
  832.             return( MEM_ERROR );
  833.         }
  834.     }        
  835.     
  836.     /*** Only after we're sure we put the request together do we add it to        ***/
  837.     /*** the queue.                                                                ***/
  838.     if( !atp->FirstRequest )
  839.         atp->FirstRequest = atp->LastRequest = qelem;
  840.     else{                                         /*** add to end of list         ***/
  841.         qp = *(atp->LastRequest);
  842.         qp->next             = qelem;
  843.         atp->LastRequest     = qelem;
  844.     }
  845.     HUnlock( qelem );
  846. }
  847.  
  848.  
  849.  
  850. short    Respond(  sp, srcAddr, theData, theSize )
  851.     ServerPtr        sp;
  852.     AddrBlock        *srcAddr;
  853.     char            *theData;
  854.     short            theSize;
  855. /*********************************
  856. * Send a response to a requesting
  857. * socket.  This is a server side
  858. * function only.
  859. *
  860. * This routine reuses the parameter
  861. * block that was used by the getrequest.
  862. * Because of this, the destination address
  863. * and the transaction ID will already be 
  864. * valid.
  865. *
  866. * In:         sp            == pointer to the server block to use
  867. *            srcAddr        == this server's address
  868. *            theData        == the data to use
  869. *            theSize        == the size of the data
  870. *
  871. * Out:        noErr if successful
  872. *            OSErr otherwise
  873. *********************************/
  874. {
  875.     /* auto */    OSErr        error     = noErr;
  876.     /* auto    */    short        bdsSize, i, bdsCount, bdsBufSiz;
  877.     register    char        *bdsPtr;
  878.     register    atpPBptr    pb         = &(sp->pb);
  879.  
  880.     /*** Note: because we are re-using the getrequest parameter block, the        ***/
  881.     /*** transaction ID and the destination address are already set in the         ***/
  882.     /*** parameter block.                                                        ***/
  883.     sp->isInUse                 = WAIT_RESPONSE;
  884.     pb->ATPioCompletion            = nil;
  885.     pb->ATPatpSocket            = srcAddr->aSocket;
  886.     pb->ATPatpFlags               = atpEOMvalue;
  887.     pb->ATPbdsPointer            = sp->rspBDS;
  888.     
  889.     /*** set up the response BDS for this transactioncopy the data into the     ***/
  890.     /*** rspbuffer (set last  byte to zero )                                    ***/
  891.     
  892.     bdsSize = ( theSize < (ATPBSIZE * MAXBDS) )? theSize : (ATPBSIZE * MAXBDS);
  893.     BlockMove( theData, sp->rspBuf, (long)bdsSize );
  894.     (sp->rspBuf)[bdsSize] = '\0';                    /*** force to a "C" string     ***/
  895.  
  896.     /*** Set up response bds by pointing into the data at ATPBSIZE intervals    ***/
  897.     
  898.     bdsPtr         = sp->rspBuf;
  899.     bdsCount     = ( bdsSize + ATPBSIZE ) / (short)ATPBSIZE;    /*** # bds elements    ***/
  900.     
  901.     for( i = 0; i < bdsCount; i++ ){
  902.         sp->rspBDS[i].buffPtr        = bdsPtr;
  903.         bdsBufSiz                    = ( bdsSize < ATPBSIZE)? bdsSize : ATPBSIZE;
  904.         sp->rspBDS[i].buffSize         = bdsBufSiz;
  905.         bdsSize -= ATPBSIZE;
  906.         if( bdsSize < 0 )
  907.             bdsSize = 0;
  908.         bdsPtr        +=    ATPBSIZE;
  909.         
  910.         /*** fix up the BDS to make it pretty for the scope ***/
  911.         sp->rspBDS[i].userBytes     = (long)'BDS0';
  912.         sp->rspBDS[i].userBytes     += (long)i;        
  913.         
  914.     }
  915.     
  916.     pb->ATPbdsSize            = (Byte)bdsCount;        /*** total # of bds elems    ***/
  917.     pb->ATPnumOfBuffs        = (Byte)bdsCount;        /*** number being sent now    ***/
  918.         
  919.     PSendResponse( pb, ASYNC );                /*** will catch the error on idle    ***/
  920.     return( error );
  921. }
  922.  
  923.  
  924. SendRequest( cp, theData, theSize, rmess, addr, count, interval )
  925.     ClientPtr        cp;
  926.     unsigned char    *theData;
  927.     short            theSize;
  928.     Handle            rmess;
  929.     AddrBlock        *addr;
  930.     short            count, interval;
  931. /*********************************
  932. * Sends the request using the transaction
  933. * block pointed to by cp. This is a client
  934. * side function only.
  935. *
  936. * In:        cp        == pointer to transaction block
  937. *            theData    == the data to use
  938. *            theSize    == the size of the data
  939. *            rmess    == the method to send back with the response
  940. *            addr    == tuple of the receiver
  941. *            retry, timeout
  942. *
  943. * Out:        noErr if successful
  944. *            OSErr otherwise
  945. *********************************/
  946. {
  947.     /* auto    */    OSErr        error = noErr;
  948.     /* auto    */    long        rsize;
  949.     /* auto    */    short        i;
  950.     /* auto    */    char        *bdsPtr;
  951.     register    atpPBptr    pb = &(cp->pb);
  952.     
  953.     cp->rspM = nil;
  954.     
  955.     /*** copy the message over ***/
  956.     if( rmess ){
  957.         rsize = GetHandleSize( rmess );
  958.         cp->rspM = NewHandle( rsize );
  959.         if( !cp->rspM )
  960.             return( DEFAULT_ERROR );
  961.         else
  962.             BlockMove( *rmess, *(cp->rspM), rsize );
  963.     }
  964.     
  965.     /*** set up the parameter block ***/
  966.     pb->ATPioCompletion        = nil;
  967.     pb->ATPuserData            = (long)0x52455153;    /*** REQS ***/    
  968.     pb->ATPatpFlags            = atpXOvalue;
  969.     pb->ATPaddrBlock.aNet    = addr->aNet;
  970.     pb->ATPaddrBlock.aNode    = addr->aNode;
  971.     pb->ATPaddrBlock.aSocket= addr->aSocket;
  972.     
  973.     /*** Set up the request BDS                                                 ***/
  974.     /*** first copy the data into the local buffer                                ***/
  975.     theSize    = (theSize < ATPBSIZE  )? theSize : ATPBSIZE;
  976.     BlockMove( theData, cp->buf, (long)theSize );
  977.     (cp->buf)[theSize]     = '\0';            /*** request MUST BE null terminated    ***/
  978.     pb->ATPreqLength    = theSize;
  979.     pb->ATPreqPointer    = cp->buf;
  980.     
  981.     /*** set up the response BDS                                                 ***/
  982.     bdsPtr    = cp->rsp;
  983.     
  984.     for( i = 0; i < MAXBDS; i++ ){
  985.         cp->bds[i].buffPtr        = bdsPtr;
  986.         cp->bds[i].buffSize        = ATPBSIZE;
  987.         cp->bds[i].dataSize        = 0;
  988.         cp->bds[i].userBytes    = 0L;
  989.         bdsPtr                    +=    ATPBSIZE;
  990.     }
  991.  
  992.     pb->ATPbdsPointer    = cp->bds;        /*** bds points to response         ***/
  993.     pb->ATPnumOfBuffs    = MAXBDS;         /*** max num of response elements    ***/
  994.     
  995.     /*** Do the timeout parameters and issue the request...                    ***/
  996.     pb->ATPtimeOutVal    = interval;
  997.     pb->ATPretryCount    = count;
  998.     cp->isInUse            = WAIT_RESPONSE;
  999.  
  1000.     error = PSendRequest( pb, ASYNC);    /*** error will be picked up later    ***/
  1001.  
  1002.     if( error >= 0 )
  1003.         error = noErr;
  1004.     else                                /*** we fell down, so deallocate    ***/
  1005.         if( cp->rspM ){ 
  1006.             HUnlock( cp->rspM );
  1007.             DisposHandle( cp->rspM );
  1008.             cp->rspM = nil;
  1009.         }
  1010.     return( error );
  1011. }
  1012.  
  1013.  
  1014. SendWaitingRequest(  atp, cp )
  1015.     ATPBlock        *atp;
  1016.     ClientPtr        cp;
  1017. /*********************************
  1018. * Attempt to send a waiting request from
  1019. * the waiting queue using the transaction
  1020. * block whose index is passed.
  1021. *
  1022. * We step through the waiting queue until
  1023. * we find the next available element.  Attempt
  1024. * to send it. If it sends ok, delete it from
  1025. * the queue, otherwise, keep it around for a
  1026. * whack at it later.
  1027. *
  1028. * In: i ==    index to available client
  1029. *            transaction block
  1030. *
  1031. *********************************/
  1032. {
  1033.     /* auto */    short        error     = noErr;    
  1034.     register    ClientQH    rq         = atp->FirstRequest;
  1035.     register    ClientQPtr    p         = nil;
  1036.     
  1037.     if( !rq )
  1038.         return( NO_ERROR );            /*** nobody in the queue             ***/
  1039.     
  1040.     MoveHHi( rq );
  1041.     HLock( rq );
  1042.     p = *rq;
  1043.     
  1044.     if( p->buf ){                    /*** only send if we have data        ***/
  1045.         MoveHHi( p->buf );
  1046.         HLock( p->buf );
  1047.         error = SendRequest(cp,*(p->buf),(short)p->size,p->rsp,&(p->addr),p->count,p->interval);    
  1048.         HUnlock( p->buf );
  1049.     }
  1050.     HUnlock( rq );
  1051.     if( !error )                        
  1052.         DeQueueRequest( atp  );        /*** got through, take the request away        ***/
  1053.         
  1054. }
  1055.  
  1056.  
  1057.  
  1058.  
  1059. /*******************************************************************\
  1060. *             Name Binding Protocol (NBP) Routines                    *
  1061. \*******************************************************************/
  1062.  
  1063. NBPBlock    *NBPInit()
  1064. /*********************************
  1065. * Initialize the NBP side for the
  1066. * network.
  1067. *
  1068. * Returns a pointer to an NBP block
  1069. * if the open was successful, nil 
  1070. * otherwise.
  1071. *
  1072. *********************************/
  1073. {
  1074.     char            *temp;
  1075.     short            i;
  1076.     NBPBlock        *nbp = nil;
  1077.     
  1078.     /*** attempt to allocate the data                 ***/
  1079.     if( !(nbp    = (Ptr)NewPtr( sizeof( NBPBlock ))) )
  1080.         return( nil );
  1081.  
  1082.     /***             ------    Initialize the NBP side    ------                ***/
  1083.     nbp->NTEntry.nt.nteAddress.aSocket    = 0;
  1084.     nbp->NTEntry.nt.nteAddress.aNode    = 0;
  1085.     nbp->NTEntry.nt.nteAddress.aNet        = 0;
  1086.     
  1087.     temp = nbp->NTEntry.nt.entityData;
  1088.     for( i = 0; i < 99; i++ )        /*** zero out the name string        ***/
  1089.         *temp++ = '\0';    
  1090.         
  1091.     nbp->LookUpBuffer    = nil;
  1092.     nbp->EntCount        = 0;
  1093.     nbp->Registered        = false;
  1094.     
  1095.     return( nbp );
  1096. }
  1097.  
  1098.  
  1099. short    NBPKill( nbp )
  1100.     NBPBlock    *nbp;
  1101. /*********************************
  1102. * Disassociate this node with the network
  1103. * and release all memory used by NBP
  1104. *
  1105. * No nbp calls are made asynchronously
  1106. * so no need to shut any of them down.
  1107. *********************************/
  1108. {
  1109.     /* auto */    OSErr            error = noErr;
  1110.     /* auto    */    char            *temp;
  1111.     /* auto */  MPPParamBlock    pb;
  1112.     
  1113.     /***     Close Down and deallocate  NBP side            ***/
  1114.     temp =     nbp->NTEntry.nt.entityData;    
  1115.     if( *temp ){
  1116.         pb.NBPentityPtr = nbp->NTEntry.nt.entityData;
  1117.         error = PRemoveName( &pb, SYNC );
  1118.     }
  1119.     
  1120.     if( nbp->LookUpBuffer ){
  1121.         HUnlock( nbp->LookUpBuffer );
  1122.         DisposHandle( nbp->LookUpBuffer );
  1123.     }
  1124.     
  1125.     DisposPtr( nbp );
  1126.     return( error );
  1127. }
  1128.  
  1129.  
  1130. short    ConfirmName(  nbp, name, addr, count, interval )
  1131.     NBPBlock        *nbp;
  1132.     EntityName        *name;
  1133.     AddrBlock        *addr;    
  1134.     short            count, interval;
  1135. /*********************************
  1136. * Confirm that the name of a network
  1137. * visible  entity is still visible
  1138. * to us.
  1139. *
  1140. * In:         name = pointer to name
  1141. *            in the form of a names table entry.
  1142. *            addr = pointer to address
  1143. *
  1144. * Out:        true     if successful, socket set in addr
  1145. *            false     otherwise
  1146. *********************************/
  1147. {
  1148.     /*auto */    OSErr            error     = noErr;
  1149.     register    MPPParamBlock    Mpb;
  1150.     
  1151.     Mpb.MPPioCompletion         =    nil;        /*** as a matter of form         ***/
  1152.     
  1153.     Mpb.NBPentityPtr            = name;
  1154.     Mpb.NBPconfirmAddr.aNet        = addr->aNet;
  1155.     Mpb.NBPconfirmAddr.aNode    = addr->aNode;
  1156.     Mpb.NBPconfirmAddr.aSocket    = addr->aSocket;
  1157.     Mpb.NBPnewSocket            = 0;
  1158.     Mpb.NBPcount                 = count;
  1159.     Mpb.NBPinterval                = interval;
  1160.     
  1161.     if( (error = PConfirmName( &Mpb, SYNC )) == noErr )
  1162.         addr->aSocket = Mpb.NBPmaxToGet;
  1163.     
  1164.     if( error  )
  1165.         return( false );
  1166.     else
  1167.         return( true );
  1168. }
  1169.  
  1170.  
  1171.  
  1172. short ExtractName(  nbp, who, name, addr )
  1173.     NBPBlock        *nbp;
  1174.     short            who;
  1175.     EntityName        *name;
  1176.     AddrBlock        *addr;
  1177. /*********************************
  1178. * Extract a name from the socket
  1179. * listening table by index.  Sets the
  1180. * send entity to this entity.
  1181. *
  1182. * In:         who            == Index to name to extract
  1183. *            name          == pointer to name result 
  1184. *            addr        == pointer to addr result
  1185. * Out:        1     if successful
  1186. *            0     if not successful
  1187. *            -1  if all entities searched
  1188. *
  1189. * Note that there is no "preferred" call
  1190. * for extract name.  Because NBPExtract 
  1191. * doesn't need a parameter block, no preferred
  1192. * call was needed.
  1193. *********************************/
  1194. {
  1195.     /* auto */    short            error;
  1196.     /* auto */    short            found = 0;
  1197.     
  1198.     if( (nbp->EntCount <= 0) || (who > nbp->EntCount) )
  1199.         return(  -1  );            /*** no network visible entities         ***/
  1200.     
  1201.     MoveHHi( nbp->LookUpBuffer );
  1202.     HLock( nbp->LookUpBuffer );
  1203.     if( !(NBPExtract( *(nbp->LookUpBuffer),nbp->EntCount,who,name,addr)) )
  1204.         found = 1;
  1205.         
  1206.     HUnlock( nbp->LookUpBuffer );
  1207.     
  1208.     return( found );
  1209. }
  1210.  
  1211.  
  1212. short    Lookup(  nbp, theType, theZone, num, count, interval )
  1213.     NBPBlock        *nbp;
  1214.     char            *theType;
  1215.     char            *theZone;
  1216.     short            num, count, interval;
  1217. /*********************************
  1218. * Lookup all network visible entities
  1219. * and fill the Lookup buffer accordingly
  1220. *
  1221. * In:         (Handle) NBPBlock
  1222. *            theType = type to lookup
  1223. *            theZone = zone to lookup
  1224. *            num        = number to lookup
  1225. *            count     = (number of retries)
  1226. *            interval= (X8 ticks)time between retries
  1227. *
  1228. * Out:        number of elements returned
  1229. *********************************/
  1230. {
  1231.     /* auto */    short            error;
  1232.     /* auto */    short            i;
  1233.     /* auto */    NamesTableEntry    nte;        /*** used internally by PLookupName    ***/
  1234.     /* auto */    long            EntSize;
  1235.     /* auto */    MPPParamBlock    Mpb;
  1236.     register    char            *np;        /*** to fill out the names table    ***/
  1237.     
  1238.     /*** resize the record ***/
  1239.     if( nbp->LookUpBuffer ){
  1240.         HUnlock( nbp->LookUpBuffer );
  1241.         DisposHandle( nbp->LookUpBuffer );
  1242.     }
  1243.     
  1244.     nbp->EntCount         = 0;
  1245.     EntSize             = ( sizeof( NamesTableEntry) );    
  1246.     nbp->LookUpBuffer     = NewHandle( (long)(num * EntSize) );
  1247.     
  1248.     if( nbp->LookUpBuffer ){
  1249.         MoveHHi( nbp->LookUpBuffer );
  1250.         HLock( nbp->LookUpBuffer );
  1251.     }
  1252.     else
  1253.         return( DEFAULT_ERROR );    /*** no room left for lookup buffer      ***/
  1254.     
  1255.     /***    Set the Search string to lookup everyone of requested type         ***/
  1256.     /***    the search string gets put away in a names table entry for         ***/
  1257.     /***     the preferred AppleTalk call                                    ***/
  1258.     /***     -----------------------------------------------------------        ***/
  1259.     /***    The use of a names table entry as opposed to an EntityName is    ***/
  1260.     /***    a matter of form.  Lookup wants to see the name in tuple form    ***/
  1261.     /***    (i.e. the entityname is packed).  We borrow the entityData from    ***/
  1262.     /***     the namestableentry element (nte) and ignore the rest of the     ***/
  1263.     /***    structure.  The use of a string[99] would have the same effect.    ***/
  1264.     
  1265.     nte.qNext                    = nil;
  1266.     nte.nt.nteAddress.aNet         = 0;
  1267.     nte.nt.nteAddress.aNode        = 0;
  1268.     nte.nt.nteAddress.aSocket    = 0;
  1269.     
  1270.     np         = nte.nt.entityData;
  1271.     *np++     = '\1';                            
  1272.     *np++     = '=';                    /*** all entities of this type please    ***/
  1273.     BlockMove( theType, np, (long)(*theType+1));
  1274.     np += (*theType)+1;
  1275.        BlockMove( theZone, np, (long)(*theZone+1) );    
  1276.  
  1277.     Mpb.NBPntQElPtr        = nte.nt.entityData;
  1278.     Mpb.NBPretBuffPtr     = *(nbp->LookUpBuffer);
  1279.     Mpb.NBPretBuffSize     = (short)(EntSize * num);
  1280.     Mpb.NBPmaxToGet        = num;
  1281.     Mpb.NBPinterval        = interval;
  1282.     Mpb.NBPcount        = count;
  1283.     
  1284.     if( !(error = PLookupName( &Mpb, SYNC)) )
  1285.         nbp->EntCount     = Mpb.NBPnumGotten;
  1286.  
  1287.     HUnlock( nbp->LookUpBuffer );
  1288.     return( nbp->EntCount );
  1289. }
  1290.  
  1291.  
  1292. short    NodeRegister(  nbp, nameOf, typeOf, count, interval, verify, addr )
  1293.     NBPBlock        *nbp;
  1294.     char            *typeOf;
  1295.     char            *nameOf;
  1296.     short            count;
  1297.     short            interval;
  1298.     short            verify;
  1299.     AddrBlock        *addr;
  1300. /*********************************
  1301. * Register this node as the entity
  1302. * passed as a parameter.
  1303. *
  1304. * In:         (Ptr)     typeof entity (provided by hyperTalk)
  1305. *            (Ptr)     nameof entity (from system resource) 
  1306. *            short    retry interval
  1307. *            short     retry count
  1308. *            short    verify = name must be unique.
  1309. * Out:        noErr if successful
  1310. *            OSErr otherwise
  1311. *********************************/
  1312. {
  1313.     /* auto */    short            error;
  1314.     register    NamesTableEntry    *nte = &(nbp->NTEntry);
  1315.     register    char            *np;        /*** pointer into names table    ***/
  1316.     /* auto */    MPPParamBlock    Mpb;
  1317.  
  1318.     /*** save off the entity in a packed names array     ***/
  1319.     np     = nte->nt.entityData;
  1320.     BlockMove( nameOf, np, (long)(*nameOf)+1 );
  1321.     np += (*nameOf)+1;
  1322.     BlockMove( typeOf, np, (long)(*typeOf)+1 );
  1323.     np += (*typeOf)+1;
  1324.     
  1325.     /*** According to Insdide AppleTalk, Zone Name must be '*' (this zone) ***/
  1326.     *np++ = '\1';
  1327.     *np++ = '*';
  1328.     
  1329.     nte->nt.nteAddress.aSocket = addr->aSocket;
  1330.     nte->nt.nteAddress.aNode = addr->aNode;
  1331.     nte->nt.nteAddress.aNet = addr->aNet;
  1332.  
  1333.     Mpb.NBPinterval        = interval;
  1334.     Mpb.NBPcount        = count;
  1335.     Mpb.NBPntQElPtr        = nte;
  1336.     Mpb.NBPverifyFlag    = verify;
  1337.     
  1338.     error = PRegisterName( &Mpb, SYNC);
  1339.     
  1340.     if( !error )
  1341.         nbp->Registered = true;
  1342.         
  1343.     return( error );
  1344. }
  1345.  
  1346.